//
// Created by Crestimes on 2024/11/18.
//

#ifndef FAMANAGER_H
#define FAMANAGER_H

#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>

#include "Fas.h"
using namespace std;

class FABuilder
{
public:
    FABuilder(map<string, string> &reMap,
              set<string> &symbols,
              size_t &NFAStart,
              size_t &DFAStart,
              size_t &MinDFAStart,
              set<size_t> &NFAEnds,
              set<size_t> &DFAEnds,
              set<size_t> &MinDFAEnds,
              vector<NFANode> &NFANodes,
              map<size_t, map<string, size_t>> &DFANodes,
              map<size_t, map<string, size_t>> &MinDFANodes,
              map<string, pair<map<size_t, map<string, size_t>>, set<size_t>>> &DFAsAndEndsOfTokenType,
              map<string, pair<map<size_t, map<string, size_t>>, set<size_t>>> &DFAsAndEndsOfAuxiliary,
              set<string> &reOfTokenType,
              set<string> &reForAuxiliary);
    // [GUI CHANGES] 使用外部引用初始化引用，让GUI能够获取到数据

    map<string, pair<map<size_t, map<string, size_t>>, set<size_t>>> DFAsAndEndsOfTokenType; // 所有正则名带_前缀的DFA图和对应的终点集
    map<string, pair<map<size_t, map<string, size_t>>, set<size_t>>> DFAsAndEndsOfAuxiliary;
    // ^^^所有会出现在reToGenerate的正则值中的正则名的DFA图和对应的终点集
    void buildDFAs(const string &reName); // [GUI CHANGES] 改为公开方法，传入正则名，生成对应自动机，数据保存到引用里，让GUI能够获取到数据

private:
    //    void buildDFAs(); // [GUI CHANGES] 建图方法公开

    // 通用成员变量
    map<string, string> &reMap; // 正则名到正则值的映射 // [GUI CHANGES] 改为引用成员变量，才能修改外部传入的引用
    set<string> reOfTokenType;  // 所有token类型对应的正则名
    set<string> reForAuxiliary; // 会出现在reOfTokenType的正则值中的正则名
    string reNameNow;           // 当前处理的正则表达式名
    string reValueNow;          // 当前处理的正则表达式值

    set<string> &symbols; // 所有符号
    set<size_t> &NFAEnds;
    size_t &NFAStart;
    set<size_t> &DFAEnds;
    size_t &DFAStart;
    set<size_t> &MinDFAEnds;
    size_t &MinDFAStart;
    // ^^^[GUI CHANGES] 改为引用成员变量，才能修改外部传入的引用，每个自动机都独立使用一个变量存储结果，外部才能获取到中间数据（NFA和DFA的数据，否则就只能获取到最终的MinDFA的数据）

    // 工具函数
    static string setToStr(const set<size_t> &epsilonSet);
    static set<size_t> strToSet(string setString);
    void clear();

    // 初始化操作
    void initBeforeGenerate(const string &reName);

    // 生成NFA
    void generateNFA();
    void initSuffixRe();
    void calcSuffixRe();
    void addNFAEdge(size_t start, size_t end, const string &symbolOnEdge);
    void createTwoNFANodes();
    NFA createNFA(const string &symbolOnEdge);
    NFA mulCalc(const NFA &);
    NFA plusCalc(const NFA &);
    NFA whatCalc(const NFA &);
    NFA orCalc(const NFA &, const NFA &);
    NFA andCalc(const NFA &, const NFA &);
    stack<char> oprStack;   // 运算符栈
    stack<NFA> NFAStack;    // Nfa栈(数字栈)
    queue<string> suffixRe; // 后缀表达式
    // ^^^使用string而不是char存是因为转义符号的存在以及类似digit这种不是指定单个char的正则名的存在，转义符号出现时需要将转义符号\和字符一起放到后缀表达式中
    vector<NFANode> &NFANodes; // 所有NFA节点 // [GUI CHANGES] 改为引用成员变量，才能修改外部传入的引用
    vector<Edge> edges;        // 所有的边
    NFA finalNFA;              // 最后生成的NFA图

    // 生成DFA
    void generateDFA();
    void initDFATemp();
    void initDFA();
    set<size_t> findNextE(size_t index);
    map<string, map<string, string>> DFANodesTemp; // 所有的DFA节点(每个string是一个点集)
    map<size_t, map<string, size_t>> &DFANodes;    // 将DFANodesTemp重新索引后的结果// [GUI CHANGES] 改为引用成员变量，才能修改外部传入的引用

    // 最小化DFA
    void minimizeDFA();
    map<size_t, map<string, size_t>> &MinDFANodes; // 最小化DFA点集// [GUI CHANGES] 改为引用成员变量，才能修改外部传入的引用

    // 打印操作
    void printNFAMatrix();
    void printDFAMatrix() const;
    void printMinDFAMatrix() const;
};

#endif // FAMANAGER_H
